#ifndef VETORTEMPLATE_H_
#define VETORTEMPLATE_H_

#include "VetorTemplateException.h"

#include "ConstantesGlobais.h"
#include "Mensagens.h"
#include <iostream>

using namespace std;
using namespace entregadepedidos::util::global;

namespace entregadepedidos{

	namespace util{

		namespace entidades{
		
			namespace vetor{

			template <class TIPO> 
			class VetorTemplate{
				
			private:

					TIPO *dados; 	// Ponteiro para meu vetor tradicional alocado dinamicamente
					int capacidade; 	// Numero de itens alocado em memoria
					int iterator; 	// Armazena a posicao de inserida do proximo elemento
					
					// Metodo Utilitario
					void geraNovoTamanho(int num_elementos_adicional)throw(VetorTemplateException);
				
				public:
					
					VetorTemplate(int tamanhoInicial = 0);
					VetorTemplate(const VetorTemplate &copia);
					virtual ~VetorTemplate();
					
					//Operacoes do vetor
					void insere(const TIPO elemento)throw(VetorTemplateException); // Excecao vetor cheio
					TIPO getPosicao(int posicao)throw(VetorTemplateException); // Excecao fora da faixa de valores validos
					void imprimeValores()throw(VetorTemplateException); // Imprime os valores do vetor
					
					// Operadores Logicos!
					bool operator==( VetorTemplate &v_dir );
					bool operator!=( VetorTemplate &v_dir );
					VetorTemplate &operator=( VetorTemplate &v_dir);
					
					//Operadores de Acesso
					TIPO operator[](int posicao);
										
				};
				
				
				template <class TIPO> 
								VetorTemplate<TIPO>::VetorTemplate(int tamanhoInicial){
													
									dados = new TIPO[tamanhoInicial];
									capacidade = tamanhoInicial;
									iterator = 0;
													
								}
																										
																										
								template <class TIPO>
								VetorTemplate<TIPO>::VetorTemplate(const VetorTemplate &copia){
													
									if(copia.capacidade > 0){
										
										dados = new TIPO[ copia.capacidade ];
															
										for(int i = 0; i < copia.iterator; i++)
											dados[i] = copia.dados[i];
															
									}else{
															
										dados = NULL;
															
									}
																												
									capacidade = copia.capacidade;
									iterator = copia.iterator;
																													
								}
																										
																										
								template <class TIPO> 
								VetorTemplate<TIPO>::~VetorTemplate(){
									delete [] dados;
								}
																										
								template <class TIPO> 
								void VetorTemplate<TIPO>::insere(TIPO elemento)throw(VetorTemplateException){
												
									try{
																												
										if (capacidade == iterator){
																														
											//Aumenta o tamanho do VetorTemplate, criando um novo e inserindo o valor
											geraNovoTamanho(10);
														
										}
																													
										dados[iterator] = elemento;
										iterator++;	
																													
										}catch(...){
											throw VetorTemplateException(ConstantesGlobais::GET_ERRO(), Mensagens::GET_VETORTEMPLATE_INSERE_ERRO());
										}	
																											
								}
																										
																										
								template <class TIPO> 
								TIPO VetorTemplate<TIPO>::getPosicao(const int posicao)throw(VetorTemplateException){
																											
									try{
																											
										if (posicao < 0 or posicao > iterator)
											throw VetorTemplateException(Mensagens::GET_VETORTEMPLATE_GETPOSICAO_POSICAO_INVALIDA(),Mensagens::GET_VETORTEMPLATE_GETPOSICAO_ERRO());
																											
									}catch(...){
										throw VetorTemplateException(ConstantesGlobais::GET_ERRO(), Mensagens::GET_VETORTEMPLATE_GETPOSICAO_ERRO());
									}
																										
									return dados[posicao];
																										
								}
																										
								template <class TIPO> 
								void VetorTemplate<TIPO>::geraNovoTamanho(int elementosAdicionais)throw(VetorTemplateException){
																											
									try{
																											
										int novoTamanho = capacidade + elementosAdicionais;
										TIPO *tmp = new TIPO[novoTamanho];
																											
										for(int i = 0; i < iterator; i++)
											tmp[i] = dados[i];
																											
										TIPO *aux = dados; // variavel auxiliar
										dados = tmp;
										delete [] aux;
										capacidade = novoTamanho;
																												
									}catch(...){
										throw VetorTemplateException(ConstantesGlobais::GET_ERRO(), Mensagens::GET_VETORTEMPLATE_GERANOVOTAMANHO_ERRO());		
									}
													
								}
																							
																							
								/**
								* Mesmo tamanho e todos os valores iguais aos valores de v_dir!!
								*/
								template <class TIPO> 
								bool VetorTemplate<TIPO>::operator==( VetorTemplate &v_dir ){
									if(iterator != v_dir.iterator)
										return false;
									
									for(int i = 0; i < iterator; i++){
										if(dados[i] != v_dir.dados[i])
											return false;
														
									}
																											
									return true;
													
								}
																										
																										
								template <class TIPO> 
								bool VetorTemplate<TIPO>::operator!=( VetorTemplate &v_dir ){
									return ( !(*this == v_dir) );
								}
																										
																										
								template <class TIPO> 
									VetorTemplate<TIPO> &VetorTemplate<TIPO>::operator=(VetorTemplate &v_dir){
																										
										if(dados != NULL)
											delete [] dados;
																														
										capacidade = v_dir.capacidade;
										iterator = v_dir.iterator;
										dados = new TIPO[capacidade];
																											
										for(int i = 0; i < iterator; i++)
											dados[i] = v_dir.dados[i];
																											
										return *this;
																												
								}
																							
																										
								template <class TIPO>
								TIPO VetorTemplate<TIPO>::operator[](const int posicao){
									return getPosicao(posicao);	
								}
																										
								template <class TIPO>
								void VetorTemplate<TIPO>::imprimeValores()throw(VetorTemplateException){
									try{
									
										for(int i = 0; i < iterator; i++)
											cout << dados[i];
										
									}catch(...){
										throw VetorTemplateException(ConstantesGlobais::GET_ERRO(), Mensagens::GET_VETORTEMPLATE_IMPRIMEVALORES_ERRO());
									}
								}

			}
			
		}
		
	}
	
}

#endif /*VETORTEMPLATE_H_*/
